#pragma once

#include "planner/optimizer_context.h"
#include "planner/optimizer_defs.h"
#include "planner/property_set.h"

struct Plan;
struct List;
struct Node;

namespace optimizer {

struct PlanResult {
  Plan *plan_;
  List *rtable_;
  List *relation_oids_;
};

/**
 * Plan Generator for generating plans from Operators
 */
class PlanGenerator {
 public:
  explicit PlanGenerator(OptimizerContext *ctx);

  PlanResult GeneratePlan(group_id_t id, PropertySet *required_props);

 private:
  struct PlanGeneratorContext {
    PropertySet *required_props_;
    Group *group_;
    GroupExpression *gexpr_;
  };

  Plan *GeneratePlanInternal(PlanGeneratorContext *ctx);

  void ApplyStatisticalProperties(Plan *plan, PlanGeneratorContext *ctx);

  Plan *GenerateSeqScanPlan(PlanGeneratorContext *ctx);

  plan_node_id_t GetNextPlanNodeID() { return plan_id_counter_++; }

  List *GenerateTargetList(PathTarget *tlist);

  /**
   * The required output property. Note that we have previously enforced
   * properties so this is fulfilled by the current operator
   */

  OptimizerContext *optimizer_context_;

  List *rtable_{nullptr};
  List *relation_oids_{nullptr};

  /**
   * Plan node counter, used to generate plan node ids
   */
  plan_node_id_t plan_id_counter_{0};
};

}  // namespace optimizer
